package com.kedacom.emptyproject.map.behavior

import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.os.Parcelable.Creator
import android.support.annotation.IntDef
import android.support.annotation.RestrictTo
import android.support.annotation.RestrictTo.Scope
import android.support.annotation.VisibleForTesting
import android.support.constraint.ConstraintLayout
import android.support.design.widget.BottomSheetBehavior
import android.support.design.widget.CoordinatorLayout
import android.support.v4.os.ParcelableCompat
import android.support.v4.os.ParcelableCompatCreatorCallbacks
import android.support.v4.view.*
import android.support.v4.view.AbsSavedState
import android.support.v4.widget.ViewDragHelper
import android.support.v4.widget.ViewDragHelper.Callback
import android.util.AttributeSet
import android.util.Log
import android.view.*
import com.kedacom.emptyproject.MainApplication
import com.kedacom.emptyproject.R
import com.kedacom.emptyproject.map.widget.MyConstraintLayoutBehaviorView
import com.kedacom.emptyproject.map.widget.MyLayerBottomInfoView
import com.kedacom.emptyproject.map.widget.MyLayerBottomRecyView
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.ref.WeakReference


/**
 * @author GuanHaoran
 * @description:
 * @date :2020/8/7 3:35 PM
 */
class MyBottomSheetBehavior<V : View>(
    context: Context,
    attrs: AttributeSet?
) : CoordinatorLayout.Behavior<V>(context, attrs) {

    constructor(ctx: Context) : this(context = ctx, attrs = null)


    interface BottomSheetCallback {

        fun onStateChanged(
            bottomSheet: View,
            @State newState: Int
        ) {
        }

        fun onSlide(bottomSheet: View, midOffset: Float, slideOffset: Float)
    }

    val lastHeight = 50
    val moreCollapsedHeight = 146


    companion object {
        //mParentHeight - mPeekHeight
        var collapsedOffset = 0

        var mViewDragHelper: ViewDragHelper? = null

        const val STATE_DRAGGING = 1//拖拽

        const val STATE_SETTLING = 2

        const val STATE_EXPANDED = 3//展开

        const val STATE_COLLAPSED = 4//收缩

        const val STATE_HIDDEN = 5

        const val STATE_COLLAPSED_MORE = 6

        /**
         * 新增状态
         */
        const val STATE_MIDDLE = 7//中建、中部

        @BottomSheetBehavior.State
        var mState = STATE_MIDDLE

        var mViewRef: WeakReference<View>? = null

        private var mCallback: BottomSheetCallback? = null

        fun setStateInternal(@BottomSheetBehavior.State state: Int) {
            if (mState == state) {
                return
            }
            mState = state
            val bottomSheet: View? = mViewRef!!.get()
            if (bottomSheet != null && mCallback != null) {
                mCallback!!.onStateChanged(bottomSheet, state)
            }
        }


        /**
         * A utility function to get the [BottomSheetBehavior] associated with the `view`.
         *
         * @param view The [View] with [BottomSheetBehavior].
         * @return The [BottomSheetBehavior] associated with the `view`.
         */
        fun <V : View> from(view: V): MyBottomSheetBehavior<V> {
            val params = view.layoutParams
            require(params is CoordinatorLayout.LayoutParams) { "The view is not a child of CoordinatorLayout" }
            val behavior = params
                .behavior
            require(behavior is MyBottomSheetBehavior<*>) { "The view is not associated with MyBottomSheetBehavior" }
            return behavior as MyBottomSheetBehavior<V>
        }


    }

    /** @hide
     */
    @RestrictTo(Scope.LIBRARY_GROUP)
    @IntDef(
        STATE_EXPANDED,
        STATE_COLLAPSED,
        STATE_DRAGGING,
        STATE_SETTLING,
        STATE_HIDDEN,
        STATE_COLLAPSED_MORE,
        STATE_MIDDLE
    )
    @Retention(RetentionPolicy.SOURCE)
    annotation class State

    /**
     * Peek at the 16:9 ratio keyline of its parent.
     *
     *
     * This can be used as a parameter for [.setPeekHeight].
     * [.getPeekHeight] will return this when the value is set.
     */
    val PEEK_HEIGHT_AUTO = -1

    private val HIDE_THRESHOLD = 0.5f

    private val HIDE_FRICTION = 0.1f

    private var mMaximumVelocity = 0f

    private var mPeekHeight = 0

    private var mPeekHeightAuto = false

    private var mPeekHeightMin = 0

    var mMinOffset = 0
    var mMiddleOffset = 0
    var mMaxOffset = 0
    var mMaxOffsetForMore = 0

    var mHideable = false

    private var mSkipCollapsed = false


    private var mIgnoreEvents = false

    private var mLastNestedScrollDy = 0

    private var mNestedScrolled = false

    var mParentHeight = 0//CoordinatorLayout的高度


    var mNestedScrollingChildRef: WeakReference<View?>? = null


    private var mVelocityTracker: VelocityTracker? = null

    var mActivePointerId = 0

    private var mInitialY = 0

    var mTouchingScrollingChild = false

    private var myLayerBottomInfoView: MyLayerBottomInfoView? = null
    private var myLayerBottomRecyView: MyLayerBottomRecyView? = null
    private var parentView: MyConstraintLayoutBehaviorView? = null

    private var MODE = 1

    init {
        mState = STATE_MIDDLE
        val a = context.obtainStyledAttributes(
            attrs,
            R.styleable.BottomSheetBehavior_Layout
        )
        val value =
            a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight)
        if (value != null && value.data == PEEK_HEIGHT_AUTO) {
            setPeekHeight(value.data)
        } else {
            setPeekHeight(
                a.getDimensionPixelSize(
                    R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, PEEK_HEIGHT_AUTO
                )
            )
        }

        MODE = a.getInt(R.styleable.BottomSheetBehavior_Layout_behavior_mode, -1)


        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false))
        setSkipCollapsed(
            a.getBoolean(
                R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed,
                false
            )
        )
        a.recycle()
        val configuration = ViewConfiguration.get(context)
        mMaximumVelocity = configuration.scaledMaximumFlingVelocity.toFloat()

    }

    /*
    fun onSaveInstanceState(parent: CoordinatorLayout?, child: V): Parcelable? {
        return SavedState(super.onSaveInstanceState(parent!!, child), mState)
    }

    fun onRestoreInstanceState(
        parent: CoordinatorLayout?,
        child: V,
        state: Parcelable
    ) {
        val ss = state as SavedState
        super.onRestoreInstanceState(parent!!, child, ss.superState!!)
        // Intermediate states are restored as collapsed state
        mState = if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
            STATE_COLLAPSED
        } else {
            ss.state
        }
    }*/

    fun testMidOffset(f: Float) {
        mMiddleOffset = ((mMaxOffset) / f).toInt()
    }

    /**
     * 在CoordinatorLayout和指定的view进行关联时调用
     * @param parent CoordinatorLayout
     * @param child 添加了Behavior的布局
     * @param layoutDirection 方向
     * @return
     */
    override fun onLayoutChild(
        parent: CoordinatorLayout,
        child: V,
        layoutDirection: Int
    ): Boolean {

        if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
            ViewCompat.setFitsSystemWindows(child, true)
        }
        val savedTop = child.top
        // First let the parent lay it out
        parent.onLayoutChild(child, layoutDirection)
        // Offset the bottom sheet
        mParentHeight = parent.height
        val peekHeight: Int
        if (mPeekHeightAuto) {
            /*   if (mPeekHeightMin == 0) {
                   mPeekHeightMin = parent.resources.getDimensionPixelSize(
                       R.dimen.design_bottom_sheet_peek_height_min
                   )
               }
               peekHeight =
                   mPeekHeightMin.coerceAtLeast(mParentHeight - parent.width * 9 / 16)*/

            if (mPeekHeightMin == 0) {
                mPeekHeightMin = parent.resources.getDimensionPixelSize(
                    R.dimen.design_bottom_sheet_peek_height_min
                )
            }
            peekHeight = 0
        } else {
            peekHeight = mPeekHeight
        }
        mMinOffset = 0.coerceAtLeast(mParentHeight - child.height)

        //  mMinOffset = dp2px(-100);
        mMaxOffset =
            (mParentHeight - peekHeight).coerceAtLeast(mMinOffset)

        mMaxOffsetForMore =
            mMaxOffset + dp2px(moreCollapsedHeight.toFloat())

//        mMiddleOffset = ((mMaxOffset) / if (MODE == 1) 1.4 else 1.7 ).toInt()
        mMiddleOffset =
            ((mMaxOffset) / if (MainApplication.UserLoginMode == 1) 1.4 else 1.7).toInt()//计算预览页面的偏移量

        /**
         * 这里根据默认的初始状态，初始化界面
         */
        if (mState == STATE_EXPANDED) {
            ViewCompat.offsetTopAndBottom(child, mMinOffset)
        } else if (mHideable && mState == STATE_HIDDEN) {
            ViewCompat.offsetTopAndBottom(child, mParentHeight - dp2px(lastHeight.toFloat()))
        } else if (mState == STATE_COLLAPSED) {
            ViewCompat.offsetTopAndBottom(child, mMaxOffset)
        } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
            ViewCompat.offsetTopAndBottom(child, savedTop - child.top)
        } else if (mState == STATE_COLLAPSED_MORE) {
            ViewCompat.offsetTopAndBottom(child, mMaxOffsetForMore)
        } else if (mState == STATE_MIDDLE) {
            ViewCompat.offsetTopAndBottom(child, mMiddleOffset)
        }
        if (mViewDragHelper == null) {
            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback)
        }
        mViewRef = WeakReference(child)
        mNestedScrollingChildRef = WeakReference(findScrollingChild(child))

        collapsedOffset = mParentHeight - mPeekHeight


        if (myLayerBottomInfoView == null && child is ConstraintLayout) {
            for (i in 0 until child.childCount) {
                if (child.getChildAt(i).tag == "layer_alarm_info" && child.getChildAt(i) is MyLayerBottomInfoView) {
                    myLayerBottomInfoView = child.getChildAt(i) as MyLayerBottomInfoView
                }
            }
        }

        if (myLayerBottomRecyView == null && child is ConstraintLayout) {
            for (i in 0 until child.childCount) {
                if (child.getChildAt(i).id == R.id.layer_alarm_list && child.getChildAt(i) is MyLayerBottomRecyView) {
                    myLayerBottomRecyView = child.getChildAt(i) as MyLayerBottomRecyView
                }
            }
        }

        if (parentView == null && child is MyConstraintLayoutBehaviorView)
            parentView = child


        return true
    }

    fun dp2px(dpValue: Float): Int {
        var scale = 0f
        if (scale == 0f) {
            scale = MainApplication.applicationContext.resources.displayMetrics.density
        }
        return (dpValue * scale + 0.5f).toInt()
        /**
         * return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
         * dpValue,
         * MyApplication.getApplication().getResources().getDisplayMetrics());
         */
    }

    override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V,
        event: MotionEvent
    ): Boolean {
        if (!child.isShown) {
            mIgnoreEvents = true
            return false
        }
        val action = MotionEventCompat.getActionMasked(event)
        // Record the velocity
        if (action == MotionEvent.ACTION_DOWN) {
            reset()
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain()
        }
        mVelocityTracker!!.addMovement(event)
        when (action) {
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                mTouchingScrollingChild = false
                mActivePointerId = MotionEvent.INVALID_POINTER_ID
                // Reset the ignore flag
                if (mIgnoreEvents) {
                    mIgnoreEvents = false
                    return false
                }
            }
            MotionEvent.ACTION_DOWN -> {
                val initialX = event.x.toInt()
                mInitialY = event.y.toInt()
                val scroll = mNestedScrollingChildRef!!.get()
                if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
                    mActivePointerId = event.getPointerId(event.actionIndex)
                    mTouchingScrollingChild = true
                }
                mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID &&
                        !parent.isPointInChildBounds(child, initialX, mInitialY)

            }
        }
        if (!mIgnoreEvents && mViewDragHelper!!.shouldInterceptTouchEvent(event)) {
            return true
        }
        // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
        // it is not the top most view of its parent. This is not necessary when the touch event is
        // happening over the scrolling content as nested scrolling logic handles that case.
        val scroll = mNestedScrollingChildRef!!.get()
        return action == MotionEvent.ACTION_MOVE && scroll != null &&
                !mIgnoreEvents && mState != STATE_DRAGGING &&
                !parent.isPointInChildBounds(scroll, event.x.toInt(), event.y.toInt()) && Math.abs(
            mInitialY - event.y
        ) > mViewDragHelper!!.touchSlop
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        if (!child.isShown) {
            return false
        }
        val action = MotionEventCompat.getActionMasked(event)
        if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
            return true
        }
        mViewDragHelper?.processTouchEvent(event)
        // Record the velocity
        if (action == MotionEvent.ACTION_DOWN) {
            reset()
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain()
        }
        mVelocityTracker!!.addMovement(event)
        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
        // to capture the bottom sheet in case it is not captured and the touch slop is passed.
        if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) {
            if (Math.abs(mInitialY - event.y) > mViewDragHelper!!.touchSlop) {
                try {
                    mViewDragHelper!!.captureChildView(child, event.getPointerId(event.actionIndex))
                } catch (e: Exception) {
                }
            }
        }
        return !mIgnoreEvents
    }

    private fun getStatusBarHeight(context: Context): Int {
        var result = 0
        val resourceId =
            context.resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) {
            result = context.resources.getDimensionPixelSize(resourceId)
        }
        return result
    }

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        nestedScrollAxes: Int
    ): Boolean {
        mLastNestedScrollDy = 0
        mNestedScrolled = false
        Log.d("qin", "onStartNestedScroll" + child.top)

        return nestedScrollAxes and ViewCompat.SCROLL_AXIS_VERTICAL != 0
    }

    /**
     * 在这里处理是否允许滑动的逻辑
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dx
     * @param dy
     * @param consumed
     */
    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray
    ) {
        Log.d("qin", "onNestedPreScroll" + child.top)
        val scrollingChild = mNestedScrollingChildRef!!.get()
        if (target !== scrollingChild) {
            return
        }
        val currentTop = child.top
        val newTop = currentTop - dy
        if (dy > 0) { // Upward
            if (newTop < mMinOffset) {
                consumed[1] = currentTop - mMinOffset
                ViewCompat.offsetTopAndBottom(child, -consumed[1])
                setStateInternal(STATE_EXPANDED)
            } else {
                consumed[1] = dy
                ViewCompat.offsetTopAndBottom(child, -dy)
                setStateInternal(STATE_DRAGGING)
            }
        } else if (dy < 0) { // Downward
            if (!ViewCompat.canScrollVertically(target, -1)) {
                //模仿原来的代码，添加一个，只要卡片距离顶端的高度小于，更加折叠状态距离顶端的高度就运行滑动
                if (newTop <= mMaxOffset || mHideable || newTop <= mMaxOffsetForMore) {
                    consumed[1] = dy
                    ViewCompat.offsetTopAndBottom(child, -dy)
                    setStateInternal(STATE_DRAGGING)
                } else {
                    consumed[1] = currentTop - mMaxOffset
                    ViewCompat.offsetTopAndBottom(child, -consumed[1])
                    setStateInternal(STATE_COLLAPSED)
                }
            }
        }
        dispatchOnSlide(child.top)
        mLastNestedScrollDy = dy
        mNestedScrolled = true
    }

    /**
     * 在我的测试中，只有拖动NestedScrollView布局里面的元素的时候，这个才会被调用，在这里处理用户放手后，滚动方向，速度和最后滚动的位置
     * @param coordinatorLayout
     * @param child
     * @param target
     */
    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View) {
        Log.d("qin", "onStopNestedScroll$mLastNestedScrollDy")
        if (child.top == mMinOffset) {
            setStateInternal(STATE_EXPANDED)
            return
        }
        if (target !== mNestedScrollingChildRef!!.get() || !mNestedScrolled) {
            return
        }
        val top: Int
        val targetState: Int
        val currentTop = child.top
        if (mLastNestedScrollDy > 0) { //由onNestedPreScroll赋值
            if (currentTop.isMiddleStatus()) {
                top = mMiddleOffset
                targetState = STATE_MIDDLE
            } else {
                /**
                 * 只要发现是向上滑动的，马上变成扩展状态，如果想先进入卡片收缩状态，可以修改这里
                 */
                top = mMinOffset
                targetState = STATE_EXPANDED
            }
        } else if (mHideable && shouldHide(child, getYVelocity())) {
            top = mParentHeight - dp2px(lastHeight.toFloat())
            targetState = STATE_HIDDEN
        } else if (mLastNestedScrollDy == 0) {
            val currentTop = child.top
            if (currentTop < mMaxOffset) {  //如果现在卡片距离是介于卡片折叠和扩展的状态
                if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
                    //卡片的状态更加接近于扩展状态
                    top = mMinOffset
                    targetState = STATE_EXPANDED
                } else {
                    //卡片的状态更加接近于折叠状态
                    top = mMaxOffset
                    targetState = STATE_COLLAPSED
                }
            } else {
                //如果现在卡片距离是介于卡片折叠和更加折叠的状态
                if (Math.abs(currentTop - mMaxOffset) < Math.abs(currentTop - mMaxOffsetForMore)) {
                    //卡片的状态更加接近于折叠状态
                    top = mMaxOffset
                    targetState = STATE_COLLAPSED
                } else {
                    //卡片的状态更加接近于更加折叠状态
                    top = mMaxOffsetForMore
                    targetState = STATE_COLLAPSED_MORE
                }
            }
        } else {
            if (currentTop.isMiddleStatus()) {
                top = mMiddleOffset
                targetState = STATE_MIDDLE
            } else {
                if (currentTop < mMaxOffset) {
                    //如果现在卡片距离是介于卡片折叠和扩展的状态，由于是向下滑动，所以直接滑动到折叠状态
                    top = mMaxOffset
                    targetState = STATE_COLLAPSED
                    Log.d("qin", "STATE_COLLAPSED==")
                } else {
                    //如果现在卡片距离是介于卡片折叠和更加折叠的状态，由于是向下滑动，所以直接滑动到更加折叠状态
                    top = mMaxOffsetForMore
                    targetState = STATE_COLLAPSED_MORE
                    Log.d("qin", "STATE_COLLAPSED_MORE==")
                }
            }
        }
        Log.d("qin", "currentTop==$top")
        if (mViewDragHelper!!.smoothSlideViewTo(child, child.left, top)) {
            setStateInternal(STATE_SETTLING)
            ViewCompat.postOnAnimation(child, SettleRunnable(child, targetState))
        } else {
            setStateInternal(targetState)
        }
        mNestedScrolled = false
    }

    override fun onNestedPreFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        return target === mNestedScrollingChildRef!!.get() &&
                (mState != STATE_EXPANDED ||
                        super.onNestedPreFling(
                            coordinatorLayout, child, target,
                            velocityX, velocityY
                        ))
    }

    /**
     * Sets the height of the bottom sheet when it is collapsed.
     *
     * @param peekHeight The height of the collapsed bottom sheet in pixels, or
     * [.PEEK_HEIGHT_AUTO] to configure the sheet to peek automatically
     * at 16:9 ratio keyline.
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
     */
    fun setPeekHeight(peekHeight: Int) {
        var layout = false
        if (peekHeight == PEEK_HEIGHT_AUTO) {
            if (!mPeekHeightAuto) {
                mPeekHeightAuto = true
                layout = true
            }
        } else if (mPeekHeightAuto || mPeekHeight != peekHeight) {
            mPeekHeightAuto = false
            mPeekHeight = Math.max(0, peekHeight)
            mMaxOffset = mParentHeight - peekHeight
            layout = true
        }
        if (layout && mState == STATE_COLLAPSED && mViewRef != null) {
            val view = mViewRef?.get()
            view?.requestLayout()
        }
    }

    /**
     * Gets the height of the bottom sheet when it is collapsed.
     *
     * @return The height of the collapsed bottom sheet in pixels, or [.PEEK_HEIGHT_AUTO]
     * if the sheet is configured to peek automatically at 16:9 ratio keyline
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
     */
    fun getPeekHeight(): Int {
        return if (mPeekHeightAuto) PEEK_HEIGHT_AUTO else mPeekHeight
    }

    /**
     * Sets whether this bottom sheet can hide when it is swiped down.
     *
     * @param hideable `true` to make this bottom sheet hideable.
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
     */
    fun setHideable(hideable: Boolean) {
        mHideable = hideable
    }

    /**
     * Gets whether this bottom sheet can hide when it is swiped down.
     *
     * @return `true` if this bottom sheet can hide.
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
     */
    fun isHideable(): Boolean {
        return mHideable
    }

    /**
     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
     * after it is expanded once. Setting this to true has no effect unless the sheet is hideable.
     *
     * @param skipCollapsed True if the bottom sheet should skip the collapsed state.
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
     */
    fun setSkipCollapsed(skipCollapsed: Boolean) {
        mSkipCollapsed = skipCollapsed
    }

    /**
     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
     * after it is expanded once.
     *
     * @return Whether the bottom sheet should skip the collapsed state.
     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
     */
    fun getSkipCollapsed(): Boolean {
        return mSkipCollapsed
    }

    /**
     * Sets a callback to be notified of bottom sheet events.
     *
     * @param callback The callback to notify when bottom sheet events occur.
     */
    fun setBottomSheetCallback(callback: BottomSheetCallback) {
        mCallback = callback
    }

    /**
     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
     * animation.
     *
     * @param state One of [.STATE_COLLAPSED], [.STATE_EXPANDED], or
     * [.STATE_HIDDEN].
     */
    fun setState(@BottomSheetBehavior.State state: Int) {
        if (state == mState) {
            return
        }
        if (mViewRef == null) {
            // The view is not laid out yet; modify mState and let onLayoutChild handle it later
            if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
                mHideable && state == STATE_HIDDEN
            ) {
                mState = state
            }
            return
        }
        val child = mViewRef?.get() ?: return
        // Start the animation; wait until a pending layout if there is one.
        val parent = child.parent
        if (parent != null && parent.isLayoutRequested && ViewCompat.isAttachedToWindow(child)) {
            child.post { startSettlingAnimation(child, state) }
        } else {
            startSettlingAnimation(child, state)
        }
    }

    /**
     * Gets the current state of the bottom sheet.
     *
     * @return One of [.STATE_EXPANDED], [.STATE_COLLAPSED], [.STATE_DRAGGING],
     * and [.STATE_SETTLING].
     */
    @BottomSheetBehavior.State
    fun getState(): Int {
        return mState
    }


    private fun reset() {
        mActivePointerId = ViewDragHelper.INVALID_POINTER
        if (mVelocityTracker != null) {
            mVelocityTracker!!.recycle()
            mVelocityTracker = null
        }
    }

    fun shouldHide(child: View, yvel: Float): Boolean {
        if (mSkipCollapsed) {
            return true
        }
        if (child.top < mMaxOffset) {
            // 它不需要隐藏  而需要直接崩溃
            return false
        }
        val newTop = child.top + yvel * HIDE_FRICTION //计算现在的距离父控件顶端的高度
        return Math.abs(newTop - mMaxOffset) / mPeekHeight.toFloat() > HIDE_THRESHOLD
    }

    /**
     * 找到view里面的第一个view
     * @param view
     * @return
     */
    private fun findScrollingChild(view: View): View? {
        if (view is NestedScrollingChild) {
            return view
        }
        if (view is ViewGroup) {
            val group = view
            var i = 0
            val count = group.childCount
            while (i < count) {
                val scrollingChild = findScrollingChild(group.getChildAt(i))
                if (scrollingChild != null) {
                    return scrollingChild
                }
                i++
            }
        }
        return null
    }

    private fun getYVelocity(): Float {
        mVelocityTracker!!.computeCurrentVelocity(1000, mMaximumVelocity)
        return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId)
    }

    fun startSettlingAnimation(child: View, state: Int) {
        Log.d("qin", "startSettlingAnimation")
        val top: Int
        top = if (state == STATE_COLLAPSED) {
            mMaxOffset
        } else if (state == STATE_EXPANDED) {
            mMinOffset
        } else if (mHideable && state == STATE_HIDDEN) {
            mParentHeight - dp2px(lastHeight.toFloat())
        } else if (state == STATE_MIDDLE) {
            mMiddleOffset
        } else {
            throw IllegalArgumentException("Illegal state argument: $state")
        }
        setStateInternal(STATE_SETTLING)
        if (mViewDragHelper!!.smoothSlideViewTo(child, child.left, top)) {
            ViewCompat.postOnAnimation(child, SettleRunnable(child, state))
        }
    }

    fun Int.isMiddleStatus(): Boolean {
        if ((this < (mMaxOffset - mMiddleOffset / 2) && this > mMiddleOffset) ||
            (this > mMiddleOffset / 2 && this < mMiddleOffset)
        ) {
            return true
        }
        return false
    }

    private val mDragCallback: Callback = object : Callback() {
        override fun tryCaptureView(child: View, pointerId: Int): Boolean {
            if (mState == STATE_DRAGGING) {
                return false
            }
            if (mTouchingScrollingChild) {
                return false
            }
            if (mState == STATE_EXPANDED && mActivePointerId == pointerId) {
                val scroll = mNestedScrollingChildRef!!.get()
                if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) {
                    // 让内容向上滚动
                    return false
                }
            }
            return mViewRef != null && mViewRef?.get() === child
        }

        override fun onViewPositionChanged(
            changedView: View,
            left: Int,
            top: Int,
            dx: Int,
            dy: Int
        ) {
            dispatchOnSlide(top)
        }

        override fun onViewDragStateChanged(state: Int) {
            if (state == ViewDragHelper.STATE_DRAGGING) {
                setStateInternal(STATE_DRAGGING)
            }
        }

        override fun onViewReleased(
            releasedChild: View,
            xvel: Float,
            yvel: Float
        ) {
            val top: Int
            val currentTop = releasedChild.top
            Log.d("qin", "onViewReleased==$yvel")
            @BottomSheetBehavior.State val targetState: Int
            if (yvel < 0) { // Moving up
                /**
                 * 只要发现是向上滑动的，马上变成扩展状态，如果想先进入卡片收缩状态，可以修改这里
                 */
//                top = mMinOffset
//                targetState = STATE_EXPANDED
                if (currentTop.isMiddleStatus()) {
                    top = mMiddleOffset
                    targetState = STATE_MIDDLE
                } else {
                    /**
                     * 只要发现是向上滑动的，马上变成扩展状态，如果想先进入卡片收缩状态，可以修改这里
                     */
                    top = mMinOffset
                    targetState = STATE_EXPANDED
                }

            } else if (mHideable && shouldHide(releasedChild, yvel)) {
//                mParentHeight=mParentHeight-100;
//                top = 100;
                top = mParentHeight - dp2px(lastHeight.toFloat())
                targetState = STATE_HIDDEN
            } else if (yvel == 0f) {
                val currentTop = releasedChild.top

                if (currentTop.isMiddleStatus()) {
                    top = mMiddleOffset
                    targetState = STATE_MIDDLE
                } else {
                    if (currentTop < mMaxOffset) {
                        if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
                            top = mMinOffset
                            targetState = STATE_EXPANDED
                        } else {
                            top = mMaxOffset
                            targetState = STATE_COLLAPSED
                        }
                    } else {
                        if (Math.abs(currentTop - mMaxOffset) < Math.abs(currentTop - mMaxOffsetForMore)) {
                            top = mMaxOffset
                            targetState = STATE_COLLAPSED
                        } else {
                            top = mMaxOffsetForMore
                            targetState = STATE_COLLAPSED_MORE
                        }
                    }
                }
            } else {

                if ((currentTop > mMaxOffset)) {
                    top = mMaxOffset
                    targetState = STATE_COLLAPSED
                } else {
                    if ((currentTop < mMiddleOffset && (currentTop > mMiddleOffset / 2)) ||
                        (currentTop > mMiddleOffset && currentTop < (mMiddleOffset + mMiddleOffset / 2))
                    ) {
                        top = mMiddleOffset
                        targetState = STATE_MIDDLE
                    } else if (currentTop < mMiddleOffset / 2) {
                        top = mMinOffset
                        targetState = STATE_EXPANDED
                    } else if (currentTop > (mMiddleOffset + mMiddleOffset / 2)) {
                        top = mMaxOffset
                        targetState = STATE_COLLAPSED
                    } else {
                        top = mMaxOffset
                        targetState = STATE_COLLAPSED
                    }
                }

            }
            if (mViewDragHelper!!.settleCapturedViewAt(releasedChild.left, top)) {
                setStateInternal(STATE_SETTLING)
                ViewCompat.postOnAnimation(
                    releasedChild,
                    SettleRunnable(releasedChild, targetState)
                )
            } else {
                setStateInternal(targetState)
            }
        }

        override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
            return MathUtils.constrain(
                top,
                mMinOffset,
                if (mHideable) mParentHeight else mMaxOffsetForMore
            )
        }

        override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
            return child.left
        }

        override fun getViewVerticalDragRange(child: View): Int {
            return if (mHideable) {
                mParentHeight - mMinOffset
            } else {
                mMaxOffsetForMore - mMinOffset
            }
        }
    }

    fun dispatchOnSlide(top: Int) {
        val bottomSheet: View? = mViewRef!!.get()
        if (bottomSheet != null && mCallback != null) {
            /* if (top > mMaxOffset) {
                 mCallback!!.onSlide(
                     bottomSheet, (mMaxOffset - top).toFloat() /
                             (mParentHeight - mMaxOffset)
                 )
             } else {
                 mCallback!!.onSlide(
                     bottomSheet,
                     (mMaxOffset - top).toFloat() / (mMaxOffset - mMinOffset)
                 )
             }*/

//            Log.e("qin","top = ${top.toFloat() }   max = $mMaxOffset  min = $mMinOffset   offset= ${(top.toFloat()-mMinOffset) / (mMaxOffset-mMinOffset)}")
            mCallback!!.onSlide(
//                bottomSheet, top.toFloat() / (mMaxOffset)
                bottomSheet,
                (mMiddleOffset - mMinOffset) / (mMaxOffset - mMinOffset).toFloat(),
                (top.toFloat() - mMinOffset) / (mMaxOffset - mMinOffset)
            )
            myLayerBottomInfoView?.setPoi(
                (mMiddleOffset - mMinOffset) / (mMaxOffset - mMinOffset).toFloat(),
                (top.toFloat() - mMinOffset) / (mMaxOffset - mMinOffset)
            )
            myLayerBottomRecyView?.setPoi(
                (mMiddleOffset - mMinOffset) / (mMaxOffset - mMinOffset).toFloat(),
                (top.toFloat() - mMinOffset) / (mMaxOffset - mMinOffset)
            )

            parentView?.setPoi(
                (mMiddleOffset - mMinOffset) / (mMaxOffset - mMinOffset).toFloat(),
                (top.toFloat() - mMinOffset) / (mMaxOffset - mMinOffset)
            )


        }
    }

    @VisibleForTesting
    fun getPeekHeightMin(): Int {
        return mPeekHeightMin
    }

    private class SettleRunnable internal constructor(
        private val mView: View,
        @field:State @param:State private val mTargetState: Int
    ) :
        Runnable {

        override fun run() {
            // Log.d("qin","SettleRunnable");
            if (mViewDragHelper != null && mViewDragHelper!!.continueSettling(true)) {
                ViewCompat.postOnAnimation(mView, this)
            } else {
                setStateInternal(mTargetState)
            }
        }

    }

    protected class SavedState : AbsSavedState {
        @BottomSheetBehavior.State
        val state: Int

        @JvmOverloads
        constructor(source: Parcel, loader: ClassLoader? = null) : super(source, loader) {
            state = source.readInt()
        }

        constructor(superState: Parcelable?, @BottomSheetBehavior.State state: Int) : super(
            superState!!
        ) {
            this.state = state
        }

        override fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            out.writeInt(state)
        }

        companion object {
            val CREATOR: Creator<SavedState?>? = ParcelableCompat.newCreator(
                object : ParcelableCompatCreatorCallbacks<SavedState?> {
                    override fun createFromParcel(
                        `in`: Parcel,
                        loader: ClassLoader
                    ): SavedState? {
                        return SavedState(`in`, loader)
                    }

                    override fun newArray(size: Int): Array<SavedState?> {
                        return arrayOfNulls(size)
                    }
                })
        }
    }


    internal object MathUtils {
        fun constrain(amount: Int, low: Int, high: Int): Int {
            return if (amount < low) low else if (amount > high) high else amount
        }

        fun constrain(amount: Float, low: Float, high: Float): Float {
            return if (amount < low) low else if (amount > high) high else amount
        }
    }

    fun getMiddleOffsetSize(): Int {
        return mMiddleOffset
    }

}